package com.hulk.ratel.web.service;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.google.common.base.Throwables;
import com.hulk.ratel.common.constant.enums.TxnLogStatus;
import com.hulk.ratel.common.constant.enums.TxnProcessStep;
import com.hulk.ratel.manage.bo.AsyncParamRespBO;
import com.hulk.ratel.manage.inner.PartnerNotifyService;
import com.hulk.ratel.manage.pass.wx.constant.WxPayConstant;
import com.hulk.ratel.manage.pass.wx.util.WxPayProperties;
import com.hulk.ratel.manage.pass.wx.util.WxPayUtil;
import com.hulk.ratel.api.notify.INotifyWxPayService;
import com.hulk.ratel.manage.service.LogTxnPayRecordService;
import com.hulk.ratel.persistence.entity.LogTxnPayRecord;
import com.hulk.ratel.persistence.mapper.LogTxnPayRecordMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;


/**
 * @author: hulk
 * @date: 17/9/10
 * @description:
 */
@Slf4j
@Service
public class NotifyWxPayServiceImpl implements INotifyWxPayService {


    @Autowired
    private LogTxnPayRecordService logTxnPayRecordService;

    @Autowired
    private PartnerNotifyService partnerNotifyService;
    @Resource
    private WxPayProperties wxPayProperties;

    @Override
    public String doWxPayNotify(String xmlResult,String workId) {
        log.info("====== 开始处理微信支付回调通知 ======");

        try {
            WxPayService wxPayService = new WxPayServiceImpl();
            WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult);
           //转换 DTO到BO，插入通知流水表 //TODO
            AsyncParamRespBO bo  = new AsyncParamRespBO();

            Map<String, Object> payContext = new HashMap<>();
            payContext.put("parameters", result);
            // 验证业务数据是否正确,验证通过后返回record和WxPayConfig对象
            if(!verifyWxPayParams(payContext)) {
                return  WxPayNotifyResponse.fail("WX返回参数验证失败");
            }


            LogTxnPayRecord record = (LogTxnPayRecord) payContext.get("txnRecord");
            WxPayConfig wxPayConfig = (WxPayConfig) payContext.get("wxPayConfig");

            wxPayService.setConfig(wxPayConfig);
            // 这里做了签名校验(这里又做了一次xml转换对象,可以考虑优化)
            wxPayService.parseOrderNotifyResult(xmlResult);



            // 更新流水
            record.setStep(TxnProcessStep.RECEIVED_ASYNC.getValue());
            record.setStatus(TxnLogStatus.SUCCESS.getValue());
            LogTxnPayRecord updateRecord = new LogTxnPayRecord();
            updateRecord.setId(record.getId());
            updateRecord.setStep(TxnProcessStep.RECEIVED_ASYNC.getValue());
            updateRecord.setStatus(TxnLogStatus.SUCCESS.getValue());
            updateRecord.setUpdatedTime(LocalDateTime.now());
			logTxnPayRecordService.updateById(updateRecord);
            // 业务系统后端通知
            partnerNotifyService.dealNotify(bo,record);
            log.info("====== 完成处理微信支付回调通知 ======");
            return WxPayNotifyResponse.success("OK");
        } catch (WxPayException e) {
            //出现业务错误
            log.error( "微信回调结果异常,result_code=FAIL,err_code:{},err_code_des:{},异常原因:{}.",e.getErrCode(),e.getErrCodeDes(), Throwables.getStackTraceAsString(e));
            return WxPayNotifyResponse.fail(e.getErrCode());
        } catch (Exception e) {
            log.error("微信回调结果异常,异常原因",e);
            return WxPayNotifyResponse.fail("未知异常");
        }
    }




    /**
     * 验证微信支付通知参数
     * @return
     */
    public boolean verifyWxPayParams(Map<String, Object> payContext) {
        WxPayOrderNotifyResult params = (WxPayOrderNotifyResult)payContext.get("parameters");

        //校验结果是否成功
        if (!WxPayConstant.RETURN_CODE_SUCCESS.equalsIgnoreCase(params.getResultCode())
                || !WxPayConstant.RESULT_CODE_SUCCESS.equalsIgnoreCase(params.getResultCode())) {
            log.error("returnCode={},resultCode={},errCode={},errCodeDes={}", params.getReturnCode(), params.getResultCode(), params.getErrCode(), params.getErrCodeDes());
            payContext.put("retMsg", "notify data failed");
            return false;
        }

        Integer totalFee = params.getTotalFee();   			// 总金额
        String outTradeNo = params.getOutTradeNo();			// 商户系统订单号

        LogTxnPayRecord record = new LogTxnPayRecord();
        record.setWorkId(Long.valueOf(outTradeNo));
        LogTxnPayRecord txnRecord = logTxnPayRecordService.getOne(new LambdaQueryWrapper<>(record));
        if(txnRecord == null){
            log.error("Can't found out_trade_no form db. out_trade_no={}, ", outTradeNo);
            payContext.put("retMsg", "Can't found out_trade_no");
            return false;
        }
        String mchId = wxPayProperties.getMchId();
        String appId = wxPayProperties.getAppId();
        String mchKey = wxPayProperties.getMchKey();

        WxPayConfig wxPayConfig = WxPayUtil.getWxPayConfig(mchId, appId, mchKey);
        payContext.put("wxPayConfig",wxPayConfig);

        // 核对金额
        long wxPayAmt = new BigDecimal(totalFee).longValue();
        long dbPayAmt = txnRecord.getTotalAmt().longValue();
        if (dbPayAmt != wxPayAmt) {
            log.error("db outTradeNo record payPrice not equals total_fee. total_fee={},outTradeNo={}", totalFee, outTradeNo);
            payContext.put("retMsg", "total_fee is not the same");
            return false;
        }
        payContext.put("txnRecord", txnRecord);
        return true;
    }




}
